package com.woniu.cms.goods.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.woniu.cms.goods.core.entity.*;
import com.woniu.cms.goods.core.exception.Asserts;
import com.woniu.cms.goods.core.exception.BusinessException;
import com.woniu.cms.goods.core.mapper.GoodsPaybackMapper;
import com.woniu.cms.goods.core.service.IGoodsGetbillMaterialService;
import com.woniu.cms.goods.core.service.IGoodsPaybackMaterialService;
import com.woniu.cms.goods.core.service.IGoodsPaybackService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.cms.goods.core.util.AspectsMsg;
import com.woniu.common.api.Result;
import com.woniu.common.api.status.Impl.BusinessCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 回缴单表 服务实现类
 * </p>
 *
 * @author romantic sheep
 * @since 2022-09-19
 */
@Service
public class GoodsPaybackServiceImpl extends ServiceImpl<GoodsPaybackMapper, GoodsPayback> implements IGoodsPaybackService {

    @Autowired
    private IGoodsPaybackMaterialService paybackMaterialService;
    @Autowired
    private IGoodsGetbillMaterialService getbillMaterialService;


    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result addPayback(GoodsPayback payback, List<GoodsPaybackMaterial> list) {
        if (ObjectUtils.isEmpty(payback)){
            return Result.error("请输入必填数据");
        }
        //先保存缴料单主表，保存失败抛出异常，事务回滚
        boolean save = this.save(payback);
        if (!save){
            Asserts.failed(AspectsMsg.SAVE_EXCEPTION);
        }
        //查询缴料单主表id，填入材料信息表外键
        LambdaQueryWrapper<GoodsPayback> qw = Wrappers.lambdaQuery();
        qw.eq(GoodsPayback::getPaybackCode,payback.getPaybackCode());
        GoodsPayback goodsPayback = this.getOne(qw);
        List<GoodsPaybackMaterial> collect = list.stream().map(e -> {
            e.setPaybackId(goodsPayback.getId());
            return e;
        }).collect(Collectors.toList());
        //保存材料信息表。保存失败则事务回滚
        boolean b = paybackMaterialService.saveBatch(collect);
        if (!b){
            Asserts.failed(AspectsMsg.SAVE_EXCEPTION);
        }
        return Result.ok(BusinessCode.ADD_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result deletePayback(Integer id, Integer status) {
        GoodsPayback goodsPayback = this.getById(id);
        if (ObjectUtils.isEmpty(goodsPayback)){
            return Result.error(BusinessCode.REMOVE_FAIL);
        }
        if (goodsPayback.getStatus()!=0&&goodsPayback.getStatus()!=3){
            return Result.error("单据已提交无法删除");
        }
        //先删除缴料单主表，删除失败则抛出异常，事务回滚。
        boolean b = this.removeById(id);
        if (!b){
            Asserts.failed(AspectsMsg.DELETE_EXCEPTION);
        }
        LambdaUpdateWrapper<GoodsPaybackMaterial> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(GoodsPaybackMaterial::getPaybackId,id);
        //再删除缴料单材料明细表，删除失败则事务回滚
        boolean remove = paybackMaterialService.remove(updateWrapper);
        if (!remove){
            Asserts.failed(AspectsMsg.DELETE_EXCEPTION);
        }
        return Result.ok(BusinessCode.REMOVE_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result updatePayback(GoodsPayback payback, List<GoodsPaybackMaterial> list) {
        if (payback.getStatus()!=0&&payback.getStatus()!=3){
            return Result.error(BusinessCode.MODIFY_FAIL);
        }
        //先修改缴料单主表，修改失败则抛出异常事务回滚
        boolean b = this.updateById(payback);
        if (!b){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        //再修改缴料单材料表，修改失败则抛出异常事务回滚
        boolean b1 = paybackMaterialService.updateBatchById(list);
        if (!b1){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        return Result.ok(BusinessCode.MODIFY_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result commitPayback(GoodsPayback payback, List<GoodsPaybackMaterial> list) {
        if (payback.getStatus()==2){
            return Result.error("单据已提交，无法重复提交");
        }
        //使用stream将材料表对应的入库材料明细表id取出
        List<Integer> ids = list.stream().map(e -> e.getGetbillMaterialId()).collect(Collectors.toList());
        //根据id查询所有对应的入库单材料明细，一个缴料单只能领用同一材料一次，所以一一对应。
        List<GoodsGetbillMaterial> getbillMaterials = getbillMaterialService.listByIds(ids);
        //对入库、缴料材料明细进行排序。排序后下标一一对应
        list.sort(new Comparator<GoodsPaybackMaterial>() {
            @Override
            public int compare(GoodsPaybackMaterial o1, GoodsPaybackMaterial o2) {
                return o1.getGetbillMaterialId()-o2.getGetbillMaterialId();
            }
        });
        getbillMaterials.sort(new Comparator<GoodsGetbillMaterial>() {
            @Override
            public int compare(GoodsGetbillMaterial o1, GoodsGetbillMaterial o2) {
                return o1.getId()-o2.getId();
            }
        });
        //循环修改库存数量。
        for (int i=0;i<list.size();i++){
            BigDecimal paybackNum = list.get(i).getPaybackNum();
            BigDecimal residueNum = getbillMaterials.get(i).getResidueNum();
            if (paybackNum.compareTo(residueNum)==1){
                return Result.error("提交失败，材料库存不足");
            }else {
                BigDecimal subtract = residueNum.subtract(paybackNum);
                GoodsGetbillMaterial goodsGetbillMaterial = getbillMaterials.get(i);
                goodsGetbillMaterial.setResidueNum(subtract);
            }
        }
        //修改缴料单状态为已提交
        payback.setStatus(1);
        //保存缴料单主表,保存失败则抛出异常事务回滚
        boolean b = this.updateById(payback);
        if (!b){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        //保存缴料单材料明细表。保存失败则抛出异常事务回滚
        boolean b1 = paybackMaterialService.updateBatchById(list);
        if (!b1){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        //保存入库单材料明细表。保存失败则抛出异常事务回滚
        boolean b2 = getbillMaterialService.updateBatchById(getbillMaterials);
        if (!b2){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        return Result.ok("单据提交成功");
    }
}
